<?php declare(strict_types=1);

namespace App\Services\Income\Strategy;

use App\Exceptions\BizException;
use App\Models\EasypayaStore;
use App\Models\EasypayStore;
use App\Models\Elec\ElecContracts;
use App\Models\IncomeStrategys;
use App\Models\Store;
use App\Models\StoreBank;
use App\Models\StoreImg;
use App\Models\StorePayWay;
use App\Models\VbillStoreCategory;
use App\Services\Income\Bootstrap;
use App\Services\Income\IncomeInterface;
use App\Services\Pay\GuoTonXinYi\BaseInfo;
use App\Services\Pay\GuoTonXinYi\Config;
use App\Services\Pay\GuoTonXinYi\Income;
use App\Vo\ResultVo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class GtxyIncomeHandler implements IncomeInterface
{

    protected function getMccId(Store $store): int
    {
        $cate = VbillStoreCategory::query()->where("id", $store->category_id)->first();
        if (empty($cate)) {
            throw new BizException("栏目不存在");
        }
//
        switch ((string)$store->store_type) {
            case "1":
                //个人开户申请
                $type = "个体工商户";
                break;
            case "2":
                //企业开户
                $type = "企业";
                break;
            case "3":
                $type = "小微商户";
                break;
        }
        $gtxyMcc = DB::table("gtxy_mccs")->where("type", $type)->where("mcc_code", $cate->mcc)->first();
        if (empty($gtxyMcc)) {
            throw new BizException("mcc不存在");
        }
        return (int)$gtxyMcc->mcc_second_id ?? 0;
    }


    public function income(string $store_id, string $company): ResultVo
    {
        $config = Bootstrap::getConfig();
        //进件参数
        $store = Store::query()->where("store_id", $store_id)->first();
        $type = Bootstrap::getApplyType((string)$store->store_type);
        $income = IncomeStrategys::query()->where(["store_id" => $store->store_id, "company" => $company])->first();
        if (empty($income)) {
            $operType = "1";
            $mchNo = "";
        } else {
            $operType = "2";
            $mchNo = $income->mch_id;
        }
        //合同类型
        $elec = ElecContracts::query()->where([
            "store_id" => $store->store_id,
            "api_type" => "gtxy",
            "company" => $company,
        ])->first();
        if (empty($elec)) {
            throw new BizException("合同不存在");
        } elseif ($elec->contractState != 1) {
            throw new BizException("合同未签约");
        }

        $storeBank = StoreBank::query()->where("store_id", $store->store_id)->first();
        if (empty($storeBank) || empty($storeBank->store_bank_no)) {
            throw new \Exception("没有绑定结算卡");
        }
        //获取费率
        $storePayWay = StorePayWay::query()->where("store_id", $store->store_id)->where("company", $company)->get()->toArray();
        $storePayWay = array_combine(array_column($storePayWay, "ways_source"), $storePayWay);
        if (empty($storePayWay)) {
            throw new BizException("先配置费率");
        }
        $stlType = [
            "D0" => [
                "type" => "0",
                "rateJs" => 0.02
            ],
            "D1" => [
                "type" => "1",
                "rateJs" => 0
            ],
            "T1" => [
                "type" => "2",
                "rateJs" => 0
            ]
        ];
        if ($storePayWay["weixin"]["settlement_type"] == "D0") {
            throw new BizException("D0请联系国通开通");
        }
        $storeImg = StoreImg::query()->where("store_id", $store->store_id)->first();
        if (empty($storeImg)) {
            throw new BizException("图片不存在");
        }
        $imgReqData = [
            "operType" => $operType, "custLogin" => $store->people_phone
        ];
        if ($operType == 2 && !empty($mchNo)) {
            $imgReqData["mchNo"] = empty($mchNo) ? "" : $mchNo;
        }
        //进件
        switch ($type) {
            case "person":
                $timestamp = Income::addCustUploadImg($imgReqData, "1", $storeImg->head_sfz_img_a, $config);
                $imgReqData["timestamp"] = $timestamp;
                Income::addCustUploadImg($imgReqData, "2", $storeImg->head_sfz_img_b, $config);
                Income::addCustUploadImg($imgReqData, "3", $storeImg->bank_img_a, $config);
                Income::addCustUploadImg($imgReqData, "4", $storeImg->store_logo_img, $config);
                Income::addCustUploadImg($imgReqData, "5", $storeImg->store_img_b, $config);
                Income::addCustUploadImg($imgReqData, "18", $storeImg->store_img_a, $config);
                Income::addCustUploadImg($imgReqData, "19", $storeImg->store_img_a_people, $config);
                $reqData = [
                    "operType" => $operType,
                    "custLogin" => $store->people_phone,
                    "busName" => $store->store_name,
                    "manageType" => "01",
                    "mcccode" => $this->getMccId($store),
                    "provId" => $store->province_code,
                    "cityId" => $store->city_code,
                    "areaId" => $store->area_code,
                    "custAddr" => $store->store_address,
                    "custName" => $store->head_name,
                    "credNo" => $store->head_sfz_no,
                    "credStartDate" => $store->head_sfz_stime,
                    "credEndDate" => $store->head_sfz_time,
                    "mobileNo" => $store->people_phone,
                    "accountName" => $storeBank->store_bank_name,
                    "accountNo" => $storeBank->store_bank_no,
                    "stlType" => $stlType[$storePayWay["weixin"]["settlement_type"]]["type"] ?? 1,
                    "rateWx" => $storePayWay["weixin"]["rate"] ?? 0,
                    "rateZfb" => $storePayWay["alipay"]["rate"] ?? 0,
                    "rateYlCap0" => $storePayWay["unionpay"]["rate_a"] ?? 0,
                    "rateYlCap1" => $storePayWay["unionpay"]["rate_c"] ?? 0,
                    "rateYlRat0" => $storePayWay["unionpay"]["rate_a"] ?? 0,
                    "rateYlRat1" => $storePayWay["unionpay"]["rate_c"] ?? 0,
                    "ratePosJy" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "ratePosJb" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "ratePosDy" => $storePayWay["unionpay"]["rate_e"] ?? 0,
                    "ratePosDb" => $storePayWay["unionpay"]["rate_e"] ?? 0,
                    "moneyPosJy" => $storePayWay["weixin"]["rate_f_top"] * 100,
                    "moneyPosJb" => $storePayWay["weixin"]["rate_f_top"] * 100,
                    "ratePosM" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "ratePosS" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "custChanType" => "0",
                    "refPower" => "1",
                    "checkCode" => $elec->checkCode,
                    "projectCode" => $elec->projectCode,
                    "timestamp" => $timestamp,
                ];
                if (!empty($mchNo)) {
                    $reqData["mchNo"] = $mchNo;
                }
                $resultVo = Income::addCustMiniApply($reqData, $config);
                break;
            case "company":
            case "person_company":
//                $reqData = BaseInfo::queryInfoByCard($storeBank->store_bank_no, $config);

                $reqData = [
                    "operType" => $operType,
                    "custLogin" => $store->people_phone,
                    "busName" => $store->store_name,
                    "refName" => mb_substr($store->store_short_name . $store->province_name . $store->city_name . $store->area_name, 0, 50),
                    "licenseno" => $store->store_license_no,
                    "busStartDate" => $store->store_license_stime,
                    "busEndDate" => $store->store_license_time,
                    "busType" => $type == "company" ? "2" : "1",
                    "mcccode" => $this->getMccId($store),
                    "provId" => $store->province_code,
                    "cityId" => $store->city_code,
                    "areaId" => $store->area_code,
                    "custAddr" => $store->store_address,
                    "custName" => $store->head_name,
                    "nolegalCertType" => "0",
                    "credNo" => $store->head_sfz_no,
                    "credStartDate" => $store->head_sfz_stime,
                    "credEndDate" => $store->head_sfz_time,
                    "mobileNo" => $store->people_phone,
                    "accountName" => $storeBank->store_bank_name,
                    "accountNo" => $storeBank->store_bank_no,
                    "stlType" => $stlType[$storePayWay["weixin"]["settlement_type"]]["type"] ?? 1,
                    "rateWx" => $storePayWay["weixin"]["rate"] ?? 0,
                    "rateZfb" => $storePayWay["alipay"]["rate"] ?? 0,
                    "rateYlCap0" => $storePayWay["unionpay"]["rate_a"] ?? 0,
                    "rateYlCap1" => $storePayWay["unionpay"]["rate_c"] ?? 0,
                    "rateYlRat0" => $storePayWay["unionpay"]["rate_a"] ?? 0,
                    "rateYlRat1" => $storePayWay["unionpay"]["rate_c"] ?? 0,
                    "ratePosJy" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "ratePosJb" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "ratePosDy" => $storePayWay["unionpay"]["rate_e"] ?? 0,
                    "ratePosDb" => $storePayWay["unionpay"]["rate_e"] ?? 0,
                    "moneyPosJy" => $storePayWay["weixin"]["rate_f_top"] * 100,
                    "moneyPosJb" => $storePayWay["weixin"]["rate_f_top"] * 100,
                    "ratePosM" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "ratePosS" => $storePayWay["unionpay"]["rate_f"] ?? 0,
                    "custChanType" => "0",
                    "refPower" => "1",
                    "checkCode" => $elec->checkCode,
                    "projectCode" => $elec->projectCode,
                ];
                $timestamp = Income::addCustUploadImg($imgReqData, "1", $storeImg->head_sfz_img_a, $config);
                $imgReqData["timestamp"] = $timestamp;
                $reqData["timestamp"] = $timestamp;
                Income::addCustUploadImg($imgReqData, "2", $storeImg->head_sfz_img_b, $config);
                Income::addCustUploadImg($imgReqData, "4", $storeImg->store_logo_img, $config);
                Income::addCustUploadImg($imgReqData, "5", $storeImg->store_img_b, $config);
                Income::addCustUploadImg($imgReqData, "12", $storeImg->store_license_img, $config);
                Income::addCustUploadImg($imgReqData, "18", $storeImg->store_img_a, $config);

                if (!empty($mchNo)) {
                    $reqData["mchNo"] = $mchNo;
                }
                if ($storeBank->store_bank_type == '01') {
                    $reqData["accountType"] = "02";
                    if ($store->cert_of_auth) {
                        $reqData["accountType"] = "03";
                        $reqData["stlName"] = $storeBank->store_bank_name;
                        $reqData["accCredType"] = "0";
                        $reqData["accCredNo"] = $store->head_sfz_no;
                        $reqData["accCredStartDate"] = $store->head_sfz_stime;
                        $reqData["accCredEndDate"] = $store->head_sfz_time;

                        Income::addCustUploadImg($imgReqData, "13", $store->head_sfz_img_a, $config);
                        Income::addCustUploadImg($imgReqData, "14", $store->head_sfz_img_b, $config);
                        Income::addCustUploadImg($imgReqData, "15", $store->cert_of_auth, $config);
                    }
                    Income::addCustUploadImg($imgReqData, "3", $storeImg->bank_img_a, $config);
                } else {
                    $reqData["accountType"] = "01";
                    $reqData["bankno"] = $storeBank->bank_no;
                    Income::addCustUploadImg($imgReqData, "3", $storeImg->store_industrylicense_img, $config);
                }

                if ($type == "company") {

                    $result = Income::addCustGetBeneficiar(["busNo" => $store->store_license_no], $config);
                    if ($result->getCode() != 1) {
                        throw new BizException($result->getMsg());
                    }
                    $beneficiarName = $result->getData()["beneficiarName"] ?? "";
                    $beneficiarStaff = $result->getData()["beneficiarStaff"] ?? "";
                    $beneficiarPercent = $result->getData()["beneficiarPercent"] ?? "";

                    $reqData["accountType"] = "02";
                    $reqData["beneficiarName"] = $beneficiarName;
                    $reqData["beneficiarStaff"] = $beneficiarStaff;
                    $reqData["beneficiarPercent"] = $beneficiarPercent;
                    $reqData["beneficiarCredNo"] = $store->head_sfz_no;
                    $reqData["beneficiarCertType"] = "0";
                    $reqData["beneficiarAddr"] = mb_substr($store->store_short_name . $store->province_name . $store->city_name . $store->area_name, 0, 50);//$store->head_sfz_address
                    $reqData["beneficiarStartTime"] = $store->head_sfz_stime;
                    $reqData["beneficiarEndTime"] = $store->head_sfz_time;
                } elseif ($type == "person_company") {
                    $reqData["accountType"] = "01";
                    $reqData["bankno"] = $storeBank->bank_no;
                } else {
                    throw new BizException("参数异常");
                }
                $resultVo = Income::addCustCommonApply($reqData, $config);
                break;
            default:
                throw new BizException("参数异常");
        }
        if ($resultVo->getCode() != 1) {
            throw new BizException($resultVo->getMsg());
        }
        $mchNoResult = $resultVo->getData()["custId"];
        $contractNo = $resultVo->getData()["contractNo"] ?? "";
        //$resultVo
        $queryMch = null;
        if ($company == "gtxy") {
            $queryMch = DB::table("common_mch_stores");
        } else if ($company == "gtxy_v2") {
            $queryMch = DB::table("common_mch_stores_v2");
        }
        if (empty($queryMch)) {
            throw new BizException("请传通道");
        }
        $mch = $queryMch->where("store_id", $store->store_id)->first();
        if (empty($mch)) {
            $queryMch->insert([
                "mch_no" => $mchNoResult,
                "store_id" => $store->store_id,
                "status" => 0,
                "company" => $company,
                "created_at" => date("Y-m-d H:i:s", time()),
                "updated_at" => date("Y-m-d H:i:s", time()),
            ]);
        } else {
            $queryMch->where(["store_id" => $store->store_id])->update([
                "mch_no" => $mchNoResult
            ]);
        }
        //更新签名
        $elec->contractNo = $contractNo;
        $elec->save();
        IncomeStrategys::query()->create(["mch_id" => $mchNoResult, "store_id" => $store->store_id, "company" => $company, "status" => 0]);
        return $resultVo;
    }

    public function incomeQuery(string $store_id, string $company): array
    {
        $store = Store::query()->where("store_id", $store_id)->first();
        if (empty($store)) {
            throw new BizException("店铺不存在");
        }
        if (StorePayWay::query()->where(["store_id" => $store->store_id, "company" => $company, "status" => 1])->exists()) {
            throw new BizException("已开通");
        }

        $income = IncomeStrategys::query()->where(["store_id" => $store->store_id, "company" => $company])->first();
        if (empty($income)) {
            throw new BizException("请先进件，在查询");
        } else if ($income->status == 1) {
            $operType = "2";
            $mchNo = $income->mch_id;
        } else {
            $operType = "0";
            $mchNo = $income->mch_id;;
        }
        if (empty($mchNo)) {
            throw new BizException("商户号不能为空");
        }
        $reqData = [
            "authType" => $operType,
        ];
        if (!empty($mchNo)) {
            $reqData["custId"] = $mchNo;
        }
        $config = Bootstrap::getConfig();
        $resultVo = Income::addCustGetResult($reqData, $config);
        if ($resultVo->getCode() != 1) {
            throw new BizException($resultVo->getMsg());
        }
        $auditResult = $resultVo->getData();
        switch ($auditResult["usrStatus"]) {
            case 0:
                $status = 0;
                $status_desc = $auditResult["authResult"] ?? "审核中";
                break;
            case 1:
                $status = 0;
                $status_desc = $auditResult["authResult"] ?? "审核中";
                break;
            case 2:
                $status = 1;
                $status_desc = "审核通过";
                break;
            case 3:
                $status = 3;
                $status_desc = $auditResult["authResult"] ?? "审核失败";
                break;
            default:
                throw new BizException("参数异常");
        }
        StorePayWay::query()->where(["store_id" => $store->store_id, "company" => $company])->update([
            "status" => $status,
            "status_desc" => $status_desc
        ]);
        $income->status = $status;
        $income->desc = $status_desc;
        $income->save();
        if ($company == "gtxy") {
            $query = DB::table("common_mch_stores");
        } else if ($company == "gtxy_v2") {
            $query = DB::table("common_mch_stores_v2");
        }
        $mch = $query->where("store_id", $store->store_id)->first();
        if (empty($mch)) {
            $query->insert([
                "mch_no" => $mchNo,
                "store_id" => $store->store_id,
                "company" => $company,
                "status" => 0
            ]);
        } else {
            $query->where("store_id", $store->store_id)->update([
                "status" => 1,
                "mch_no" => $mchNo
            ]);
        }
        return ["status" => $status];
    }

    public function incomeNotify(array $data)
    {
//        error_log(date('Y-m-d H:i:s') . " 【银盛进件回调】： " . json_encode([$data]) . "\n\n", 3, "/tmp/" . 'ys-add-mch' . date('Ymd') . ".log");
        Log::channel("income")->info("incomeNotify", $data);
        $config = Bootstrap::getConfig();
        if ($data["agetId"] != $config["agetId"]) {
            throw new BizException("机构号不一致");
        }
        $pdata = $data["pdata"];

        $decodeString = Config::decode($pdata, $config["public_key"]);
        $pdata = json_decode($decodeString, true);
        //验证签名
        $mchNo = $pdata["CUST_ID"] ?? "";

        $auditResult = $pdata["AUTH_RESULT"] ?? "";
        $income = IncomeStrategys::query()->where(["mch_id" => $mchNo])->first();
        if (empty($income)) {
            throw new BizException("进件记录不存在");
        }
        $company = $income->company;

        switch ($company) {
            case "gtxy":
                $queryBuilder = DB::table("common_mch_stores");
                break;
            case "gtxy_v2":
                $queryBuilder = DB::table("common_mch_stores_v2");
                break;
        }
        $companyStore = $queryBuilder->where("mch_no", $mchNo)->first();
        if (empty($companyStore)) {
            throw new BizException("商户号不存在");
        }


        switch ($auditResult) {
            case "00":
                $income->status = 1;
                $income->desc = "审核通过";
                $income->save();
                $queryBuilder->where("mch_no", $mchNo)->update(["status" => 1]);
                StorePayWay::query()
                    ->where(['store_id' => $companyStore->store_id, 'company' => $company])
                    ->update([
                        'status' => 1,
                        'status_desc' => '开通成功',
                        'created_at' => date('Y-m-d H:i:s'),
                        'updated_at' => date('Y-m-d H:i:s'),
                    ]);
                break;
            default:
                $income->status = 0;
                $income->desc = $pdata["NOT_THROW_REASON"];
                $income->save();

                $queryBuilder->where("mch_no", $mchNo)->update(["status" => 1]);

                StorePayWay::query()
                    ->where(['store_id' => $companyStore->store_id, 'company' => $company])
                    ->update([
                        'status' => 0,
                        'status_desc' => $pdata["NOT_THROW_REASON"],
                        'updated_at' => date('Y-m-d H:i:s'),
                    ]);
        }
        return json_encode([
            "rspCod" => "",
            "rspMsg" => "success"
        ]);
    }

}